import { useEffect } from "react";
import { useIntl } from "react-intl";
import { useEffectOnce } from "react-use";
import { filter, fromEvent, interval, merge } from "rxjs";

import { useAppMonitoringService } from "./AppMonitoringService";
import { useNotificationService } from "./Notification";

interface BuildInfo {
  build: string;
}

const LAST_UPDATE_CHECK_KEY = "lastUpdateCheckTimestamp";

const INTERVAL = 60_000;
const MINIMUM_WAIT_BEFORE_REFETCH = 3 * 24 * 60 * 60 * 1000; // 3 days

/**
 * This hook sets up a check to /buildInfo.json, which is generated by the build system on every build
 * with a new hash. If it ever detects a new hash in it, we know that the Airbyte instance got updated
 * and show a notification to the user to reload the page.
 */
export const useBuildUpdateCheck = () => {
  const { formatMessage } = useIntl();
  const { registerNotification } = useNotificationService();
  const { trackError } = useAppMonitoringService();

  useEffectOnce(() => {
    // Set the last update check to the timestamp when the page is loaded, so we won't check for another x days from now
    window.sessionStorage.setItem(LAST_UPDATE_CHECK_KEY, String(Date.now()));
  });

  useEffect(() => {
    // Trigger the check every ${INTERVAL} milliseconds or whenever the window regains focus again
    const subscription = merge(interval(INTERVAL), fromEvent(window, "focus"))
      .pipe(
        filter(() => {
          // Only run actual check if the previous check was more than MINIMUM_WAIT_BEFORE_REFETCH ago
          const lastUpdateCheck = window.sessionStorage.getItem(LAST_UPDATE_CHECK_KEY);
          return !lastUpdateCheck || Date.now() - Number(lastUpdateCheck) > MINIMUM_WAIT_BEFORE_REFETCH;
        })
      )
      .subscribe(async () => {
        window.sessionStorage.setItem(LAST_UPDATE_CHECK_KEY, String(Date.now()));

        try {
          // Fetch the buildInfo.json file without using any browser cache
          const buildInfo: BuildInfo = await fetch("/buildInfo.json", { cache: "no-store" }).then((resp) =>
            resp.json()
          );

          if (buildInfo.build !== process.env.BUILD_HASH) {
            registerNotification({
              id: "webapp-updated",
              text: formatMessage({ id: "notifications.airbyteUpdated" }),
              timeout: false,
              actionBtnText: formatMessage({ id: "notifications.airbyteUpdated.reload" }),
              onAction: () => window.location.reload(),
            });
          }
        } catch (e) {
          // We ignore all errors from the build update check, since it's an optional check to
          // inform the user. We don't want to treat failed requests here as errors.
          trackError(e);
        }
      });

    return () => {
      subscription.unsubscribe();
    };
  }, [formatMessage, registerNotification, trackError]);
};
